#include <cstddef>
#include <cstdint>

/**
 * @brief 基于块链（block chain）的内存管理方法
 * 参考链接 http://allenchou.net/2013/05/memory-management-part-1-of-3-the-allocator/
 */



namespace My {

    struct BlockHeader
    {
        // union-ed with data
        BlockHeader* pNext;
    };

    struct PageHeader
    {
        PageHeader* pNext;
        BlockHeader* Blocks() {
            return reinterpret_cast<BlockHeader*>(this + 1);
        }
    };

    class Allocator
    {
        public:
            // debug patterns
            static const uint8_t PATTERN_ALIGN = 0xFC;
            static const uint8_t PATTERN_ALLOC = 0xFD;
            static const uint8_t PATTERN_FREE  = 0xFE;

            Allocator() = default;
            Allocator(size_t data_size, size_t page_size, size_t alignment);
            ~Allocator();

            // reset the allocator to a new configuration
            void Reset(size_t data_size, size_t page_size, size_t alignment);

            // alloc and free blocks
            void* Allocate();
            void Free(void* p);
            void FreeAll();

        private :
#if defined(_DEBUG)
            // fill a free page with debug patterns
            void FillFreePage(PageHeader* pPage);
            
            // fill a block with debug patterns
            void FillFreeBlock(BlockHeader* pBlock);

            // fill an allocated block with debug patterns
            void FillAllocatedBlock(BlockHeader* pBlock); 
#endif

            // get the next block
            BlockHeader* NextBlock(BlockHeader* pBlock);

            // the page list
            PageHeader* m_pPageList;

            // the free block list
            BlockHeader* m_pFreeList;

            size_t      m_szDataSize;
            size_t      m_szPageSize;
            size_t      m_szAlignmentSize;
            size_t      m_szBlockSize;
            uint32_t    m_nBlocksPerPage;

            // statistics
            uint32_t    m_nPages;
            uint32_t    m_nBlocks;
            uint32_t    m_nFreeBlocks;

            // disable copy & allignment;
            Allocator(const Allocator& clone);
            Allocator &operator=(const Allocator &rhs);
    };
}
